home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / domhdr.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  13KB  |  510 lines

  1. /* Domain header conversion routines
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Additional support for the Domain Name Server
  5.  * by Johan. K. Reinalda, WG7J,
  6.  * based on previous work by Gerard v.d. Grinten, PA0GRI
  7.  */
  8.  
  9. /****************************************************************************
  10. *    $Id: domhdr.c 1.4 94/01/04 14:09:15 ROOT_DOS Exp $
  11. *    17 May 93    1.3        GT    Fix warnings.                                    *
  12. *    29 Dec 93    1.4        GT    Fix conditionals.                                *
  13. ****************************************************************************/
  14.  
  15. #include "global.h"
  16. #include "config.h"
  17. #include "mbuf.h"
  18. #include "domain.h"
  19.  
  20. static int dn_expand __ARGS((char *msg,char *eom,char *compressed,char *full,
  21.     int fullen));
  22. static char *getq __ARGS((struct rr **rrpp,char *msg,char *cp));
  23. static char *ntohrr __ARGS((struct rr **rrpp,char *msg,char *cp));
  24.  
  25. #ifdef DSERVER
  26. static char *dn_compress(char *cp, char *name);
  27. static char *htonrr(struct rr *rr, char *buffer);
  28. #endif
  29.  
  30. int
  31. ntohdomain(dhdr,bpp)
  32. struct dhdr *dhdr;
  33. struct mbuf **bpp;
  34. {
  35.     int16 tmp,len;
  36.     register int16 i;
  37.     char *msg,*cp;
  38.     struct rr **rrpp;
  39.  
  40.     len = len_p(*bpp);
  41.     msg = mallocw(len);
  42.     pullup(bpp,msg,len);
  43.     memset((char *)dhdr,0,sizeof(*dhdr));
  44.  
  45.     dhdr->id = get16(&msg[0]);
  46.     tmp = get16(&msg[2]);
  47.     if(tmp & 0x8000)
  48.         dhdr->qr = 1;
  49.     dhdr->opcode = (tmp >> 11) & 0xf;
  50.     if(tmp & 0x0400)
  51.         dhdr->aa = 1;
  52.     if(tmp & 0x0200)
  53.         dhdr->tc = 1;
  54.     if(tmp & 0x0100)
  55.         dhdr->rd = 1;
  56.     if(tmp & 0x0080)
  57.         dhdr->ra = 1;
  58.     dhdr->rcode = tmp & 0xf;
  59.     dhdr->qdcount = get16(&msg[4]);
  60.     dhdr->ancount = get16(&msg[6]);
  61.     dhdr->nscount = get16(&msg[8]);
  62.     dhdr->arcount = get16(&msg[10]);
  63.  
  64.     /* Now parse the variable length sections */
  65.     cp = &msg[12];
  66.  
  67.     /* Question section */
  68.     rrpp = &dhdr->questions;
  69.     for(i=0;i<dhdr->qdcount;i++){
  70.         if((cp = getq(rrpp,msg,cp)) == NULLCHAR){
  71.             free(msg);
  72.             return -1;
  73.         }
  74.         (*rrpp)->source = RR_QUESTION;
  75.         rrpp = &(*rrpp)->next;
  76.     }
  77.     *rrpp = NULLRR;
  78.  
  79.     /* Answer section */
  80.     rrpp = &dhdr->answers;
  81.     for(i=0;i<dhdr->ancount;i++){
  82.         if((cp = ntohrr(rrpp,msg,cp)) == NULLCHAR){
  83.             free(msg);
  84.             return -1;
  85.         }
  86.         (*rrpp)->source = RR_ANSWER;
  87.         rrpp = &(*rrpp)->next;
  88.     }
  89.     *rrpp = NULLRR;
  90.  
  91.     /* Name server (authority) section */
  92.     rrpp = &dhdr->authority;
  93.     for(i=0;i<dhdr->nscount;i++){
  94.         if((cp = ntohrr(rrpp,msg,cp)) == NULLCHAR){
  95.             free(msg);
  96.             return -1;
  97.         }
  98.         (*rrpp)->source = RR_AUTHORITY;
  99.         rrpp = &(*rrpp)->next;
  100.     }
  101.     *rrpp = NULLRR;
  102.  
  103.     /* Additional section */
  104.     rrpp = &dhdr->additional;
  105.     for(i=0;i<dhdr->arcount;i++){
  106.         if((cp = ntohrr(rrpp,msg,cp)) == NULLCHAR){
  107.             free(msg);
  108.             return -1;
  109.         }
  110.         (*rrpp)->source = RR_ADDITIONAL;
  111.         rrpp = &(*rrpp)->next;
  112.     }
  113.     *rrpp = NULLRR;
  114.     free(msg);
  115.     return 0;
  116. }
  117. static char *
  118. getq(rrpp,msg,cp)
  119. struct rr **rrpp;
  120. char *msg;
  121. char *cp;
  122. {
  123.     register struct rr *rrp;
  124.     int len;
  125.     char *name;
  126.  
  127.     *rrpp = rrp = (struct rr *)callocw(1,sizeof(struct rr));
  128.     name = mallocw(512);
  129.     len = dn_expand(msg,NULLCHAR,cp,name,512);
  130.     if(len == -1){
  131.         free(name);
  132.         return NULLCHAR;
  133.     }
  134.     cp += len;
  135.     rrp->name = strdup(name);
  136.     rrp->type = get16(cp);
  137.     cp += 2;
  138.     rrp->class = get16(cp);
  139.     cp += 2;
  140.     rrp->ttl = 0;
  141.     rrp->rdlength = 0;
  142.     free(name);
  143.     return cp;
  144. }
  145. /* Read a resource record from a domain message into a host structure */
  146. static char *
  147. ntohrr(rrpp,msg,cp)
  148. struct rr **rrpp; /* Where to allocate resource record structure */
  149. char *msg;    /* Pointer to beginning of domain message */
  150. char *cp;    /* Pointer to start of encoded RR record */
  151. {
  152.     register struct rr *rrp;
  153.     int len;
  154.     char *name;
  155.  
  156.     *rrpp = rrp = (struct rr *)callocw(1,sizeof(struct rr));
  157.     name = mallocw(512);
  158.     if((len = dn_expand(msg,NULLCHAR,cp,name,512)) == -1){
  159.         free(name);
  160.         return NULLCHAR;
  161.     }
  162.     cp += len;
  163.     rrp->name = strdup(name);
  164.     rrp->type = get16(cp);
  165.     cp += 2;
  166.     rrp->class = get16(cp);
  167.     cp+= 2;
  168.     rrp->ttl = get32(cp);
  169.     cp += 4;
  170.     rrp->rdlength = get16(cp);
  171.     cp += 2;
  172.     switch(rrp->type){
  173.     case TYPE_A:
  174.         /* Just read the address directly into the structure */
  175.         rrp->rdata.addr = get32(cp);
  176.         cp += 4;
  177.         break;
  178.     case TYPE_CNAME:
  179.     case TYPE_MB:
  180.     case TYPE_MG:
  181.     case TYPE_MR:
  182.     case TYPE_NS:
  183.     case TYPE_PTR:
  184.         /* These types all consist of a single domain name;
  185.          * convert it to ascii format
  186.          */
  187.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  188.         if(len == -1){
  189.             free(name);
  190.             return NULLCHAR;
  191.         }
  192.         rrp->rdata.name = strdup(name);
  193.         rrp->rdlength = strlen(name);
  194.         cp += len;
  195.         break;
  196.     case TYPE_HINFO:
  197.         len = *cp++;
  198.         rrp->rdata.hinfo.cpu = mallocw(len+1);
  199.         memcpy( rrp->rdata.hinfo.cpu, cp, len );
  200.         rrp->rdata.hinfo.cpu[len] = '\0';
  201.         cp += len;
  202.  
  203.         len = *cp++;
  204.         rrp->rdata.hinfo.os = mallocw(len+1);
  205.         memcpy( rrp->rdata.hinfo.os, cp, len );
  206.         rrp->rdata.hinfo.os[len] = '\0';
  207.         cp += len;
  208.         break;
  209.     case TYPE_MX:
  210.         rrp->rdata.mx.pref = get16(cp);
  211.         cp += 2;
  212.         /* Get domain name of exchanger */
  213.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  214.         if(len == -1){
  215.             free(name);
  216.             return NULLCHAR;
  217.         }
  218.         rrp->rdata.mx.exch = strdup(name);
  219.         cp += len;
  220.         break;
  221.     case TYPE_SOA:
  222.         /* Get domain name of name server */
  223.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  224.         if(len == -1){
  225.             free(name);
  226.             return NULLCHAR;
  227.         }
  228.         rrp->rdata.soa.mname = strdup(name);
  229.         cp += len;
  230.  
  231.         /* Get domain name of responsible person */
  232.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  233.         if(len == -1){
  234.             free(name);
  235.             return NULLCHAR;
  236.         }
  237.         rrp->rdata.soa.rname = strdup(name);
  238.         cp += len;
  239.  
  240.         rrp->rdata.soa.serial = get32(cp);
  241.         cp += 4;
  242.         rrp->rdata.soa.refresh = get32(cp);
  243.         cp += 4;
  244.         rrp->rdata.soa.retry = get32(cp);
  245.         cp += 4;
  246.         rrp->rdata.soa.expire = get32(cp);
  247.         cp += 4;
  248.         rrp->rdata.soa.minimum = get32(cp);
  249.         cp += 4;
  250.         break;
  251.     case TYPE_TXT:
  252.         /* Just stash */
  253.         rrp->rdata.data = mallocw(rrp->rdlength);
  254.         memcpy(rrp->rdata.data,cp,rrp->rdlength);
  255.         cp += rrp->rdlength;
  256.         break;
  257.     default:
  258.         /* Ignore */
  259.         cp += rrp->rdlength;
  260.         break;
  261.     }
  262.     free(name);
  263.     return cp;
  264. }
  265.  
  266. /* Convert a compressed domain name to the human-readable form */
  267. static int
  268. dn_expand(msg,eom,compressed,full,fullen)
  269. char *msg;        /* Complete domain message */
  270. char *eom;
  271. char *compressed;    /* Pointer to compressed name */
  272. char *full;        /* Pointer to result buffer */
  273. int fullen;        /* Length of same */
  274. {
  275.     unsigned int slen;    /* Length of current segment */
  276.     register char *cp;
  277.     int clen = 0;    /* Total length of compressed name */
  278.     int indirect = 0;    /* Set if indirection encountered */
  279.     int nseg = 0;        /* Total number of segments in name */
  280.  
  281.     cp = compressed;
  282.     for(;;){
  283.         slen = uchar(*cp++);    /* Length of this segment */
  284.         if(!indirect)
  285.             clen++;
  286.         if((slen & 0xc0) == 0xc0){
  287.             if(!indirect)
  288.                 clen++;
  289.             indirect = 1;
  290.             /* Follow indirection */
  291.             cp = &msg[((slen & 0x3f)<<8) + uchar(*cp)];
  292.             slen = uchar(*cp++);
  293.         }
  294.         if(slen == 0)    /* zero length == all done */
  295.             break;
  296.         fullen -= slen + 1;
  297.         if(fullen < 0)
  298.             return -1;
  299.         if(!indirect)
  300.             clen += slen;
  301.         while(slen-- != 0)
  302.             *full++ = *cp++;
  303.         *full++ = '.';
  304.         nseg++;
  305.     }
  306.     if(nseg == 0){
  307.         /* Root name; represent as single dot */
  308.         *full++ = '.';
  309.         fullen--;
  310.     }
  311.     *full++ = '\0';
  312.     fullen--;
  313.     return clen;    /* Length of compressed message */
  314. }
  315.  
  316.  
  317.  
  318. #ifdef DSERVER
  319.  
  320. /* Most of this code is based on the DNS server in PA0GRI's 910828
  321.  * Ported to the current NOS code by Johan. K. Reinalda, WG7J
  322.  * for version and bug/feature info, see domain.c
  323.  */
  324.  
  325. static char *
  326. dn_compress(cp,name)
  327. char *cp, *name;
  328. {
  329.     int len,dlen;
  330.     char *cp1;
  331.     dlen = strlen(name);
  332.     for(;;){
  333.         /* Look for next dot */
  334.         cp1 = strchr(name,'.');
  335.         if(cp1 != NULLCHAR)
  336.             len = (int) (cp1 - name);    /* More to come */
  337.         else
  338.             len = dlen;    /* Last component */
  339.         *cp++ = len;        /* Write length of component */
  340.         if(len == 0)
  341.             return cp;
  342.         /* Copy component up to (but not including) dot */
  343.         strncpy(cp,name,len);
  344.         cp += len;
  345.         if(cp1 == NULLCHAR){
  346.             *cp++ = 0;    /* Last one; write null and finish */
  347.             return cp;
  348.         }
  349.         name += len+1;
  350.         dlen -= len+1;
  351.     }
  352. }
  353.  
  354. /* Translate a resource record from host format to network format */
  355. static char *
  356. htonrr(rr,buffer)
  357. struct rr *rr;
  358. char *buffer;
  359. {
  360.     struct rr *rrp;
  361.     char *cp, *p;
  362.     int i, len;
  363.  
  364.     cp = buffer;
  365.     for(rrp = rr; rrp != NULLRR; rrp = rrp->next) {
  366. #ifdef notdef
  367.         i = strlen(rrp->name);
  368.         if(rrp->name[i-1] != '.'
  369.            && rrp->origin != NULLCHAR) {
  370.             p = mallocw(i + strlen(rrp->origin) + 2);
  371.             sprintf(p,"%s.%s",rrp->name,rrp->origin);
  372.             cp = dn_compress(cp,p);
  373.             free(p);
  374.         } else
  375. #endif
  376.             cp = dn_compress(cp,rrp->name);
  377.         cp = put16(cp,rrp->type);
  378.         cp = put16(cp,rrp->class);
  379.         cp = put32(cp,rrp->ttl);
  380. #ifdef notdef
  381.         /* The length doesn't seem to be right for all types ! */
  382.         cp = put16(cp,rrp->rdlength);
  383. #endif
  384.         p = cp;     /* This is where the length goes ! */
  385.         cp += 2;    /* Save the space for lenght field */
  386.  
  387.         switch(rrp->type) {
  388.         case TYPE_A:
  389.             cp = put32(cp,rrp->rdata.addr);
  390.             break;
  391.         case TYPE_SOA:
  392.             cp = dn_compress(cp,rrp->rdata.soa.mname);
  393.             cp = dn_compress(cp,rrp->rdata.soa.rname);
  394.             cp = put32(cp,rrp->rdata.soa.serial);
  395.             cp = put32(cp,rrp->rdata.soa.refresh);
  396.             cp = put32(cp,rrp->rdata.soa.retry);
  397.             cp = put32(cp,rrp->rdata.soa.expire);
  398.             cp = put32(cp,rrp->rdata.soa.minimum);
  399.             break;
  400.         case TYPE_HINFO:
  401.             *cp++ = len = strlen(rrp->rdata.hinfo.cpu); 
  402.             strncpy(cp,rrp->rdata.hinfo.cpu,len); 
  403.             cp += len;
  404.             *cp++ = len = strlen(rrp->rdata.hinfo.os);
  405.             strncpy(cp,rrp->rdata.hinfo.os,len); 
  406.             cp += len;
  407.             break;
  408.         case TYPE_MX:
  409.             cp = put16(cp,rrp->rdata.mx.pref); 
  410.             cp = dn_compress(cp,rrp->rdata.mx.exch);
  411.             break;
  412.         case TYPE_CNAME:
  413.         case TYPE_MB:
  414.         case TYPE_MG:
  415.         case TYPE_MR:
  416.         case TYPE_NS:
  417.         case TYPE_PTR:
  418.             cp = dn_compress(cp,rrp->rdata.data);
  419.             break;
  420.         case TYPE_MINFO:    /* Unsupported type */
  421.         cp = dn_compress(cp,rrp->rdata.minfo.rmailbx);
  422.         cp = dn_compress(cp,rrp->rdata.minfo.emailbx);
  423.         case TYPE_MD:       /* Unsupported type */
  424.         case TYPE_MF:       /* Unsupported type */
  425.         case TYPE_NULL:     /* Unsupported type */
  426.         case TYPE_WKS:      /* Unsupported type */
  427.             cp = dn_compress(cp,rrp->rdata.data);
  428.             break;
  429.         case TYPE_TXT:
  430.         default:
  431.             cp = put16(cp,rrp->rdlength);
  432.             for(i=0 ; i < rrp->rdlength ; i++)
  433.                 *cp++ = rrp->rdata.data[i];
  434.             break;
  435.         }
  436.         /* Calculate the lenght of the RR */
  437.         len = (int) (cp - p - 2);
  438.         put16(p,len);       /* and set it */
  439.     }
  440.     return cp;
  441. }
  442.  
  443. int
  444. htondomain(
  445.     struct dhdr *dhdr,
  446.     char *buffer,            /* Area for query */
  447.     int16 buflen)            /* Length of same */
  448. {
  449.     char *cp;
  450.     struct rr *rrp;
  451.     int16 parameter;
  452.     int i, count;
  453.  
  454.     cp = buffer;
  455.     cp = put16(cp,dhdr->id);    
  456.     if(dhdr->qr)
  457.         parameter = 0x8000;
  458.     else
  459.         parameter = 0;
  460.     parameter |= (dhdr->opcode & 0x0f) << 11;
  461.     if(dhdr->aa)
  462.         parameter |= DOM_AUTHORITY;
  463.     if(dhdr->tc)
  464.         parameter |= DOM_TRUNC;
  465.     if(dhdr->rd)
  466.         parameter |= DOM_DORECURSE;
  467.     if(dhdr->ra)
  468.         parameter |= DOM_CANRECURSE;
  469.     parameter |= (dhdr->rcode & 0x0f);
  470.     cp = put16(cp,parameter);
  471.     cp = put16(cp,dhdr->qdcount);
  472.     cp = put16(cp,dhdr->ancount);
  473.     cp = put16(cp,dhdr->nscount);
  474.     cp = put16(cp,dhdr->arcount);
  475.     if((count = dhdr->qdcount) > 0) {
  476.         rrp = dhdr->questions;
  477.         for(i = 0; i < count; i++) {
  478.             cp = dn_compress(cp,rrp->name);
  479.             cp = put16(cp,rrp->type);
  480.             cp = put16(cp,rrp->class);
  481.             rrp = rrp->next;
  482.         }
  483.     }
  484.     if((count = dhdr->ancount) > 0) {
  485.         rrp = dhdr->answers;
  486.         for(i = 0; i < count; i++) {
  487.             cp = htonrr(rrp,cp);
  488.             rrp = rrp->next;
  489.         }
  490.     }
  491.     if((count = dhdr->nscount) > 0) {
  492.         rrp = dhdr->authority;
  493.         for(i = 0; i < count; i++) {
  494.             cp = htonrr(rrp,cp);
  495.             rrp = rrp->next;
  496.         }
  497.     }
  498.     if((count = dhdr->arcount) > 0) {
  499.         rrp = dhdr->additional;
  500.         for(i = 0; i < count; i++) {
  501.             cp = htonrr(rrp,cp);
  502.             rrp = rrp->next;
  503.         }
  504.     }
  505.     return (int) (cp - buffer);
  506. }
  507.  
  508.  
  509. #endif
  510.